/*
    路由模块的实现：功能性模块
*/

#pragma once
#include "../common/logger.hpp"
#include "../common/helper.hpp"
#include "../common/message.pb.h"
#include <cctype>
#include <vector>

namespace mq
{
    class Router
    {
    public:
        // 判断是否是合法routing key
        static bool isLegalRoutingKey(const std::string& routing_key)
        {
            /*
                由[a~z][A~Z][0~9]._构成
            */
            for(auto ch : routing_key)
            {
                if(isalnum(ch) || ch == '.' || ch == '_')
                    continue;
                return false;
            }
            return true;
        }

        // 判断是否是合法binding key
        static bool isLegalBindingKey(const std::string& binding_key)
        {
            /*
                由[a~z][A~Z][0~9]._*#构成，*和#只能单独作为单词出现，*和#不能连续出现
            */
            // 1. 非法字符判断
            for(auto ch : binding_key)
            {
                if(isalnum(ch) || ch == '.' || ch == '_' || ch == '*' || ch == '#')
                    continue;
                return false;
            }

            // 2. *和#只能单独做单词
            std::vector<std::string> words;
            StringHelper::split(binding_key, ".", words);
            for(auto& word : words)
            {
                if(word.size() > 1 && (word.find("*") != std::string::npos || word.find("#") != std::string::npos))
                    return false;
            }


            // 3. *和#不能连续出现
            for(int i = 1; i < words.size(); i++)
            {
                if((words[i] == "#" && words[i-1] == "*") 
                || (words[i] == "*" && words[i-1] == "#") 
                || (words[i] == "#" && words[i-1] == "#"))
                    return false;
            }
            return true;
        }

        // 判断routing key能否路由到binding key
        static bool route(ExchangerType type, const std::string& routing_key, const std::string& binding_key)
        {
            /*
                动态规划的思想
            */
            if(type == ExchangerType::FANOUT)
            {
                return true;
            }
            else if(type == ExchangerType::DIRECT)
            {
                return routing_key == binding_key;
            }
            else if(type == ExchangerType::TOPIC)
            {
                return route_handler(routing_key, binding_key);
            }
            return false;
        }
    private:
        static bool route_handler(const std::string& routing_key, const std::string& binding_key)
        {
            std::vector<std::string> routing_words;
            std::vector<std::string> binding_words;
            StringHelper::split(routing_key, ".", routing_words);
            StringHelper::split(binding_key, ".", binding_words);
            int n = routing_words.size(), m = binding_words.size();
            std::vector<std::vector<bool>> dp(n+1, std::vector<bool>(m+1, false));
            dp[0][0] = true;
            if(binding_words[0] == "#") dp[0][1] = true;
            for(int i = 1; i <= n; i++)
            {
                for(int j = 1; j <= m; j++)
                {
                    if(binding_words[j-1] == "#")
                        dp[i][j] = dp[i-1][j-1] || dp[i-1][j] || dp[i][j-1];
                    else if(binding_words[j-1] == "*" || routing_words[i-1] == binding_words[j-1])
                        dp[i][j] = dp[i-1][j-1];
                }
            }
            return dp[n][m];
        }
    };
}